/**
 * @Title: Utils
 * @Author  dudalei
 * @Package
 * @Date  2024/11/8 08:57
 * @description: 提供一些工具方法
 */
import { Box3, MathUtils, Object3D, PerspectiveCamera, Vector3 } from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

/**
 * 移动相机到指定位置
 * @param root 模型或者物体
 * @param sizeToFitOnScreen 适合屏幕大小
 * @param maxDistance  最大距离
 * @param controls 轨道控制器
 * @param camera 相机
 */
export function frameArea(
  root: Object3D,
  sizeToFitOnScreen: number = 0.5,
  maxDistance = 10,
  controls: OrbitControls,
  camera: PerspectiveCamera,
  offset: Vector3 = new Vector3(0, 0, 0),
) {
  const box = new Box3().setFromObject(root)
  const boxSize = box.getSize(new Vector3()).length()
  const boxCenter = box.getCenter(new Vector3(0, 0, 0))

  const halfSizeToFitOnScreen = boxSize * sizeToFitOnScreen
  const halfFovY = MathUtils.degToRad(camera.fov * 0.5)
  const distance = halfSizeToFitOnScreen / Math.tan(halfFovY)
  // 计算指向相机当前方向的单位向量
  // 在从长方体中心的 xz 平面中
  const direction = new Vector3()
    .subVectors(camera.position, boxCenter)
    .multiply(new Vector3(1, 0, 1))
    .normalize()

  const v = direction.multiplyScalar(distance).add(boxCenter).add(offset)
  console.log('相机位置', v)
  // 将相机移动到距中心以 distance 单位为单位的位置
  // 无论摄像机从中心朝哪个方向
  camera.position.copy(v)

  // 为 frustum 选择一些 near 和 far 值，这些
  // 将包含该框。
  camera.near = boxSize / 100
  camera.far = boxSize * 100

  camera.updateProjectionMatrix()

  // 将相机对准框的中心
  camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z)

  controls.maxDistance = boxSize * maxDistance
  controls.target.copy(boxCenter)
  controls.update()
}
